﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Kugar.Core.ExtMethod
{
    public static class DateTimeExt
    {
        /// <summary>
        ///     修改日期中的年份
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="year">要修改的日期值,取值范围:0001-9999,该取值需按照正确日期取值,否则将抛出错误</param>
        /// <returns>返回设置了日期值的新的datetime值</returns>
        public static DateTime SetYear(this DateTime dt, int year)
        {
            
            return new DateTime(year, dt.Month, dt.Day, dt.Minute, dt.Minute, dt.Second, dt.Millisecond, dt.Kind);
        }

        /// <summary>
        ///     修改日期中的月份
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="month">要修改的日期值,取值范围:1-12,该取值需按照正确日期取值,否则将抛出错误</param>
        /// <returns>返回设置了日期值的新的datetime值</returns>
        public static DateTime SetMonth(this DateTime dt, int month)
        {
            if (month.IsNotBetween(1, 12))
            {
                throw new ArgumentOutOfRangeException();
            }

            return new DateTime(dt.Year, month, dt.Day, dt.Minute, dt.Minute, dt.Second, dt.Millisecond, dt.Kind);
        }

        /// <summary>
        ///     修改日期中的日期
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="day">要修改的日期值,取值范围:1-31,该取值需按照正确日期取值,否则将抛出错误</param>
        /// <returns>返回设置了日期值的新的datetime值</returns>
        public static DateTime SetDay(this DateTime dt, int day)
        {
            if (day.IsNotBetween(1, 31))
            {
                throw new ArgumentOutOfRangeException();
            }

            return new DateTime(dt.Year, dt.Month, day, dt.Minute, dt.Minute, dt.Second, dt.Millisecond, dt.Kind);
        }

        /// <summary>
        ///     修改日期中的小时数
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="hours">要修改的小时值,取值范围:0-23</param>
        /// <returns>返回设置了小时值的新的datetime值</returns>
        public static DateTime SetHour(this DateTime dt,int hours)
        {
            if (hours.IsNotBetween(0,23))
            {
                throw new ArgumentOutOfRangeException();
            }

            return new DateTime(dt.Year, dt.Month, dt.Day, hours,dt.Minute, dt.Second, dt.Millisecond, dt.Kind);
        }

        /// <summary>
        ///     修改日期中的分钟数
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="minute">要修改的分钟值,取值范围:0-59</param>
        /// <returns>返回设置了小时值的新的datetime值</returns>
        public static DateTime SetMinute(this DateTime dt, int minute)
        {
            if (minute.IsNotBetween(0, 59))
            {
                throw new ArgumentOutOfRangeException();
            }

            return new DateTime(dt.Year, dt.Month, dt.Day, dt.Minute, minute, dt.Second, dt.Millisecond, dt.Kind);
        }

        /// <summary>
        ///     修改日期中的秒数
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="second">要修改的分钟值,取值范围:0-59</param>
        /// <returns>返回设置了秒数值的新的datetime值</returns>
        public static DateTime SetSecond(this DateTime dt, int second)
        {
            if (second.IsNotBetween(0, 59))
            {
                throw new ArgumentOutOfRangeException();
            }

            return new DateTime(dt.Year, dt.Month, dt.Day, dt.Minute, dt.Minute, second, dt.Millisecond, dt.Kind);
        }


        public static DateTime SetStartTime(this DateTime dt)
        {
            return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0);
        }

        public static DateTime SetEndTime(this DateTime dt)
        {
            return new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59);
        }

        public static DateTime NextWeek(this DateTime dt)
        {
            return NextWeek(dt, dt.DayOfWeek);
        }

        public static DateTime NextWeek(this DateTime dt,DayOfWeek week)
        {
            var td = Math.Abs((week == DayOfWeek.Sunday ? 7 : (int)week )- (dt.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)week));



            return dt.AddDays(td==0?7:td);
        }

        public static DateTime ThisWeek(this DateTime dt,DayOfWeek week)
        {
            if (week==dt.DayOfWeek)
            {
                return dt;
            }

            return dt.AddDays(-1*((int) dt.DayOfWeek - (int) week));
        }



        /// <summary>
        ///     将UTC时间转换为当前系统的本地时间
        /// </summary>
        /// <param name="dateTimeUtc">源UTC时间</param>
        /// <returns></returns>
        public static DateTime ToLocalDateTime(this DateTimeOffset dateTimeUtc)
        {
            return ToLocalDateTime(dateTimeUtc,null);
        }

        /// <summary>
        ///     将UTC时间转换为指定的当地时间
        /// </summary>
        /// <param name="dateTimeUtc">源UTC时间</param>
        /// <param name="localTimeZone">目的本地时间</param>
        /// <returns></returns>
        public static DateTime ToLocalDateTime(this DateTimeOffset dateTimeUtc, TimeZoneInfo localTimeZone)
        {
            localTimeZone = (localTimeZone ?? TimeZoneInfo.Local);

            return TimeZoneInfo.ConvertTime(dateTimeUtc, localTimeZone).DateTime;
        }




        public static bool Equals(this DateTime srcTime,DateTime compareTime,DateTimeCompareParts partsFlag)
        {
            if (partsFlag.IsContans(DateTimeCompareParts.Tick) && srcTime.Ticks != compareTime.Ticks) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Year) && srcTime.Year != compareTime.Year) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Month) && srcTime.Month != compareTime.Month) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Day) && srcTime.Day != compareTime.Day) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Hour) && srcTime.Hour != compareTime.Hour) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Minute) && srcTime.Minute != compareTime.Minute) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Second) && srcTime.Second != compareTime.Second) return false;
            if (partsFlag.IsContans(DateTimeCompareParts.Millisecond) && srcTime.Millisecond != compareTime.Millisecond) return false;
            return true;
        }

    }

    [Flags]
    public enum DateTimeCompareParts
    {
        Tick=0,
        Year=1,
        Month=2,
        Day=4,
        Hour=8,
        Minute=16,
        Second=32,
        Millisecond=64

    }
}
